<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.global.js"></script>
</head>

<body>
    <div id="app">
        <button @click="stopEffect">stop</button>
        <p ref="p">{{a}}</p>
        <p>
            <button @click="addA">a++</button>
        </p>
        <hr>
        <p>{{zhang.name}}---{{zhang.age}}</p>
        <p>
            <button @click="changeName">changeName</button>
            <button @click="changeAge">changeAge</button>
        </p>
    </div>
</body>
<script>
    // Vue3  => Vue的第三个大版本修改  
    // 相较于Vue2  
    // 1. 选项式语法做了修改  



    // Vue3
    // 1. Vue  => 全局对象  => {createApp,nextTick,ref,reactive}
    // 2. Vue中对象存有创建引用的方法  var {createApp} = Vue;
    // 3. Vue3的选项式语法中 没有el属性 => 通过app.mount() 指定挂载的元素
    // 4. Vue3的选项式语法中 data是一个返回对象的函数  => 所有的组件均是如此 
    // 5. Vue3中 data methods computed 不在存储在Vue组件(实例)上  => 而是单独存储到一个对象上(代理对象 proxy)  =>  方法中的this默认都指向代理对象  => 取值和赋值都通过代理对象执行
    // 6. Vue3中 全局属性 组件 指令 插件 都是依赖于app定义的

    // 组合式语法

    console.log(Vue);

    var { createApp, nextTick } = Vue;
    var { ref, reactive, readonly, computed,watch,watchEffect } = Vue;
    var app = createApp({
        // 组合式
        setup: function (props) {
            console.log("setup钩子函数开始执行");

            // watchEffect(callback,options)
            // callback  => 回调函数
            // options   => {flush:"sync/pre/post"}

            // 立即运行一个函数，同时响应式地追踪其依赖，并在依赖更改时重新执行。
            // 1. watchEffect传入一个函数,该函数会立即执行
            // 2. watchEffect()中的函数可以设置多个依赖(数据/计算属性),当依赖更改是重新执行函数

            // 返回值: stop函数 => 调用该函数停止watchEffect


            // 可以理解为是:computed和watch的组合版

            // 对比computed
            // 共同点:
            // 1. 初始化阶段立即执行(watchEffect-> setup函数中立即执行  computed-> created)
            // 2. 都可以有多个响应式依赖  
            // 区别:
            // 1. computed计算属性 => 要根据依赖得到新值,  watchEffect会在依赖更改是重新执行函数
            // 2. watchEffect 可以接收第二参数, {flush:"pre/sync/post"}  => computed不行


            // 对比watch
            // 共同点:
            // 1. 可以通过参数控制 回调函数执行的时机 {flush:"pre/sync/post"} 

            // 区别:
            // 1. watch是惰性的,在数据改变之后才会执行,  watchEffect初始化阶段立即执行(setup函数中立即执行
            // 2. watch监听数据是可以获取newVal,oldVal  => 数据更改前后的变化
            //    watchEffect => 更注重数据发生改变之后 => 重新执行函数, 没有旧值 只有新值


            var a = ref(10); // {value:10}
            // console.log("a",a);
            var zhang = reactive({name:"张飒",age:18}); // new Proxy(target,{get,set})
            // console.log("reactive",zhang);

            function getData(){
                console.log("a的值发生改变",a.value);
                console.log("zhang的值发生改变",zhang.name,zhang.age);
            }

            var stop = watchEffect(function(){
                getData();
            },{flush:"post"})


            let stopEffect = ()=>{
                stop();
            }



            // 定义方法 methods
            function addA() {
                a.value++;
            }

            function changeName(){
                zhang.name='李四'
            }
            function changeAge(){
                zhang.age++
            }



            // 闭包  => setup函数中返回的数据/计算属性/方法/监听  就是后面选项式语法中接收的
            // 对象中的键名 => 后面选项式语法中proxy代理对象中的属性名
            // 对象中的键值 => setup函数中的对象 方法
            return {
                a: a, // a:ref对象
                addA: addA,
                zhang,
                changeName,
                changeAge,
                stopEffect
            }
        },
        // 选项式
        // data(){},
        // computed:{},
        // methods:{},
        // watch:{},

        beforeCreate() {
            console.log("beforeCreate", this);
            // console.log("beforeCreate",this.a);  // proxy对象取值是进行了解包  this.a => ref.value;

            // this.a = 100;   // ref.value = 100;
            // console.log("beforeCreate",this.a); // this.a => ref.value;

        },

        created() {
            console.log("created", this);
        },
        mounted() {
            console.log("组件挂载完毕",this);
        },
    })

    console.log("app", app);
    app.mount("#app");




</script>



</html>